package org.orbis.memoryblock.invert;

import java.nio.ByteBuffer;
import org.orbis.communicate.FlagsResult;
import org.orbis.communicate.indexer.term.TermPackage;
import org.orbis.memorymanager.filter.DeleteFilter;
import org.orbis.structure.LookupPointer;

public class OptimizerInvertIndexBlock extends InvertIndexBlock{
	public OptimizerInvertIndexBlock(ByteBuffer existingBody){
		super(existingBody);
	}

	public LookupPointer advancePointer(LookupPointer ptr){
		int perUser =
			option[OPT_BOOLARR] + (INT * option[OPT_INTFLAG]) + (LONG * option[OPT_LONGFLAG])
				+ (FLOAT * option[OPT_FLOATFLAG]) + LONG;
		int newPoint = ptr.point() + NEWEST + (option[OPT_TERMNUM] * perUser);
		if(newPoint + NEWEST + (option[OPT_TERMNUM] * perUser) >= getBodySize()) return LookupPointer.EMPTY;
		return ptr.modify(ptr.block(), newPoint);
	}

	public void setBack(FlagsResult[] results, int ptr){
		int newestPtr = ptr;

		ptr += NEWEST;
		int i = 0;
		for(; i < option[OPT_TERMNUM]; i++){
			if(results[i] == null) break;
			store(TermPackage.flagToByte(results[i].binaryFlags()), ptr);
			ptr += option[OPT_BOOLARR];

			int[] intFlags = results[i].intFlags();
			for(int j = 0; j < option[OPT_INTFLAG]; j++){
				setInt(ptr, INT, intFlags[j]);
				ptr += INT;
			}

			long[] longFlags = results[i].longFlags();
			for(int j = 0; j < option[OPT_LONGFLAG]; j++){
				setLong(ptr, LONG, longFlags[j]);
				ptr += LONG;
			}

			float[] floatFlags = results[i].floatFlags();
			for(int j = 0; j < option[OPT_FLOATFLAG]; j++){
				setFloat(ptr, floatFlags[j]);
				ptr += FLOAT;
			}

			setLong(ptr, LONG, results[i].ID());
			ptr += LONG;
		}

		// Newest number
		setInt(newestPtr, INT, i);
	}

	// Find whole memory space and to get IDs whose flag filters
	public FlagsResult[] pickIDbyFlag(DeleteFilter filter, int ptr){
		FlagsResult[] pickedIDs = new FlagsResult[option[OPT_TERMNUM]];
		int count = 0;
		boolean isSkip;

		isSkip = false;
		ptr += NEWEST;
		for(int i = 0; i < option[OPT_TERMNUM]; i++){
			if(pickedIDs[count] == null)
				pickedIDs[count] =
					new FlagsResult(option[OPT_BOOLFLAG], option[OPT_INTFLAG], option[OPT_LONGFLAG],
						option[OPT_FLOATFLAG]);
			pickedIDs[count].setBinaryFlags(TermPackage.byteToFlag(read(ptr, option[OPT_BOOLARR]),
				option[OPT_BOOLFLAG]));
			ptr += option[OPT_BOOLARR];

			// Int flag
			int[] intFlags = new int[option[OPT_INTFLAG]];
			for(int k = 0; k < option[OPT_INTFLAG]; k++){
				intFlags[k] = getInt(ptr, INT);
				if(filter.filterIntFlag(k, intFlags[k])){
					isSkip = true;
					ptr +=
						((option[OPT_INTFLAG] - k) * INT) + (option[OPT_LONGFLAG] * LONG)
							+ (option[OPT_FLOATFLAG] * FLOAT) + LONG;
					break;
				}
				ptr += INT;
			}
			if(isSkip) continue;
			pickedIDs[count].setIntFlags(intFlags);

			// Long flag
			long[] longFlags = new long[option[OPT_LONGFLAG]];
			for(int k = 0; k < option[OPT_LONGFLAG]; k++){
				longFlags[k] = getLong(ptr, LONG);
				if(filter.filterLongFlag(k, longFlags[k])){
					isSkip = true;
					ptr += ((option[OPT_LONGFLAG] - k) * LONG) + (option[OPT_FLOATFLAG] * FLOAT) + LONG;
					break;
				}
				ptr += LONG;
			}
			if(isSkip) continue;
			pickedIDs[count].setLongFlags(longFlags);

			float[] floatFlags = new float[option[OPT_FLOATFLAG]];
			for(int j = 0; j < option[OPT_FLOATFLAG]; j++){
				floatFlags[j] = getFloat(ptr);
				ptr += FLOAT;
			}
			pickedIDs[count].setFloatFlags(floatFlags);
			long ID = getLong(ptr, LONG);
			if(ID == 0){
				pickedIDs[count] = null;
				break;
			}
			ptr += LONG;
			if(filter.filterID(ID)) continue;
			pickedIDs[count].setID(ID);

			count++;
		}
		if(count == 0 && pickedIDs[0] == null) return null;

		return pickedIDs;
	}
}
